using System;
using System.Xml;
using System.Globalization;

using DesignByContract;

using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition{
    public class PointBuilder : BuilderBase{
        #region Attributes

        private string fontColorAttr = "font-color";
        private string fontDecorationAttr = "font-decoration";
        private string fontNameAttr = "font-name";
        private string fontSizeAttr = "font-size";
        private string hAlignAttr = "halign";
        private string useTextAttr = "use-text";

        #endregion

        private readonly string mNodeName = XmlTagNames.point.ToString();

        private XmlNode mNode;

        private string mNodePath{
            get { return "./" + mNodeName; }
        }

        public override void SelectNode(XmlDocument document){
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Compose(){
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Compose(XmlNode node){
            mNode = node; //.SelectSingleNode(mNodePath);
            try{
                BuildObject(mNode);
            }
            catch (PreconditionException preExc){
                LogManager.Instance.LogWarning("Point entity could not be created; process aborted.", preExc);
            }
        }

        public override void AppendToParent(object parent){
            Check.Require(parent is PointCollection, "Parent object not a valid argument");

            (parent as PointCollection).Add((Point) mProduct);
        }

        private void BuildObject(XmlNode pointXmlNode){
            var point = new Point();
            try{
                //font attributes
                if (pointXmlNode.Attributes[fontNameAttr] != null)
                    point.FontName = ParseFontNameAttribute(pointXmlNode);
                if (pointXmlNode.Attributes[fontSizeAttr] != null)
                    point.FontSize = ParseFontSizeAttribute(pointXmlNode);
                if (pointXmlNode.Attributes[fontDecorationAttr] != null){
                    point.IsFontBold = ParseIsFontBoldAttribute(pointXmlNode);
                    point.IsFontItalic = ParseIsFontItalicAttribute(pointXmlNode);
                    point.IsFontUnderline = ParseIsFontUnderlineAttribute(pointXmlNode);
                }
                if (pointXmlNode.Attributes[fontColorAttr] != null)
                    point.Color = ParseColorAttribute(pointXmlNode);

                if (pointXmlNode.Attributes[hAlignAttr] != null)
                    point.HorizontalAlignment = ParseHorizontalAlignmentAttribute(pointXmlNode);
                if (pointXmlNode.Attributes[useTextAttr] != null)
                    point.UseText = ParseUseTextAttribute(pointXmlNode);
                if (!point.UseText)
                    point.Value = ParseValue(pointXmlNode);
            }
            catch (PreconditionException preExc){
                //log error
                point = null;
                throw;
            }

            mProduct = point;
        }

        private double ParseValue(XmlNode pointXmlNode){
            if (String.IsNullOrEmpty(pointXmlNode.InnerText))
                return Double.NaN;
            return Double.Parse(pointXmlNode.InnerText, CultureInfo.InvariantCulture.NumberFormat);
        }

        private bool ParseUseTextAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[useTextAttr] != null, "use-text attribute not present");
            return Boolean.Parse(pointXmlNode.Attributes[useTextAttr].Value);
        }

        private PPAlignment ParseHorizontalAlignmentAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[hAlignAttr] != null, "horizontal alignment attribute not present");
            return ConvertHorizontalAlignFromName(pointXmlNode.Attributes[hAlignAttr].Value);
        }

        private PPAlignment ConvertHorizontalAlignFromName(string value){
            switch (value){
                case "ppAlignCenter":
                    return PPAlignment.ppAlignCenter;
                    break;
                case "ppAlignDistribute":
                    return PPAlignment.ppAlignDistribute;
                    break;
                case "ppAlignJustify":
                    return PPAlignment.ppAlignJustify;
                    break;
                case "ppAlignLeft":
                    return PPAlignment.ppAlignLeft;
                    break;
                case "ppAlignRight":
                    return PPAlignment.ppAlignRight;
                    break;
            }
            return PPAlignment.ppAlignUnknown;
        }

        private string ParseFontNameAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontNameAttr] != null, "font-name attribute not present");
            return pointXmlNode.Attributes[fontNameAttr].Value;
        }

        private int ParseFontSizeAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontSizeAttr] != null, "font-size attribute not present");
            return Int32.Parse(pointXmlNode.Attributes[fontSizeAttr].Value);
        }

        private bool ParseIsFontBoldAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return pointXmlNode.Attributes[fontDecorationAttr].Value.Contains("bold");
        }

        private bool ParseIsFontItalicAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return pointXmlNode.Attributes[fontDecorationAttr].Value.Contains("italic");
        }

        private bool ParseIsFontUnderlineAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return pointXmlNode.Attributes[fontDecorationAttr].Value.Contains("underline");
        }

        private long ParseColorAttribute(XmlNode pointXmlNode){
            Check.Require(pointXmlNode.Attributes[fontColorAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(pointXmlNode.Attributes[fontColorAttr].Value);
        }
    }
}